{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 四、卷积神经网络\n",
    "(Convolutional Neural Networks, CNN)\n",
    "## 4.1 基本概念\n",
    "卷积神经网络（CNN）是一种专门处理具有类似网格结构的数据的神经网络，如图像。CNN 的主要特点是它可以自动并适应地学习局部空间的输入特征。这使得 CNN 在处理图像、视频、语音和文本等数据时具有很高的效率和准确率。\n",
    "## 4.2 关键技术\n",
    "CNN 的关键技术包括卷积层、池化层和全连接层。<br/>\n",
    "![cnn](../images/4-cnn.webp)<br/>\n",
    "卷积层：卷积层是 CNN 的核心，它通过卷积操作来提取输入数据的特征。卷积操作可以用以下数学公式表示:<br/>\n",
    "![cnn-math](../images/4-cnn-math.webp)<br/>\n",
    "其中， 是输入数据， 是卷积核，∗ 表示卷积操作。<br/>\n",
    "池化层：池化层是用来降低数据的维度，从而减少计算量和防止过拟合。常见的池化操作包括最大池化和平均池化。<br/>\n",
    "全连接层：全连接层通常位于 CNN 的最后几层，用来整合所有特征并输出最终结果。<br/>\n",
    "## 4.3 应用领域\n",
    "CNN 广泛应用于图像识别、视频分析、语音识别、自然语言处理等领域。著名的深度学习模型如 LeNet、AlexNet、VGG、ResNet 都是基于 CNN 的。<br/>\n",
    "## 4.4 优点\n",
    "CNN 的主要优点是可以自动并适应地学习局部空间的输入特征，这使得 CNN 在处理图像、视频、语音和文本等数据时具有很高的效率和准确率。\n",
    "## 4.5 缺点\n",
    "CNN 的主要缺点是需要大量的数据和计算资源来训练，而且对于超参数的选择非常敏感。\n",
    "## 4.6 实例分析\n",
    "LeNet、AlexNet、VGG 和 ResNet 是一些著名的基于 CNN 的深度学习模型。它们在图像识别等任务上取得了显著的成果。\n",
    "## 4.7 手动实现\n",
    "以下是一个简单的 CNN 的 Python 实现："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'torch'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mtorch\u001b[39;00m\n\u001b[1;32m      2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mtorch\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mnn\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mnn\u001b[39;00m\n\u001b[1;32m      3\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mtorch\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mnn\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfunctional\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mF\u001b[39;00m\n",
      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'torch'"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "from torchvision import datasets, transforms\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 定义 CNN 类\n",
    "class SimpleCNN(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(SimpleCNN, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(1, 20, 5, 1)\n",
    "        self.conv2 = nn.Conv2d(20, 50, 5, 1)\n",
    "        self.fc1 = nn.Linear(4*4*50, 500)\n",
    "        self.fc2 = nn.Linear(500, 10)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = F.relu(self.conv1(x))\n",
    "        x = F.max_pool2d(x, 2, 2)\n",
    "        x = F.relu(self.conv2(x))\n",
    "        x = F.max_pool2d(x, 2, 2)\n",
    "        x = x.view(-1, 4*4*50)\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = self.fc2(x)\n",
    "        return F.log_softmax(x, dim=1)\n",
    "\n",
    "# 加载数据\n",
    "transform=transforms.Compose([\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize((0.1307,), (0.3081,))\n",
    "    ])\n",
    "dataset1 = datasets.MNIST('./data', train=True, download=True, transform=transform)\n",
    "dataset2 = datasets.MNIST('./data', train=False, transform=transform)\n",
    "train_loader = torch.utils.data.DataLoader(dataset1, batch_size=64, shuffle=True)\n",
    "test_loader = torch.utils.data.DataLoader(dataset2, batch_size=1000, shuffle=True)\n",
    "\n",
    "# 初始化网络和优化器\n",
    "model = SimpleCNN()\n",
    "optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.5)\n",
    "\n",
    "# 训练网络\n",
    "def train(epoch):\n",
    "    for batch_idx, (data, target) in enumerate(train_loader):\n",
    "        optimizer.zero_grad()\n",
    "        output = model(data)\n",
    "        loss = F.nll_loss(output, target)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        if batch_idx % 100 == 0:\n",
    "            print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n",
    "                epoch, batch_idx * len(data), len(train_loader.dataset),\n",
    "                100. * batch_idx / len(train_loader), loss.item()))\n",
    "\n",
    "# 测试网络\n",
    "def test():\n",
    "    test_loss = 0\n",
    "    correct = 0\n",
    "    for data, target in test_loader:\n",
    "        output = model(data)\n",
    "        test_loss += F.nll_loss(output, target, reduction='sum').item()\n",
    "        pred = output.data.max(1, keepdim=True)[1]\n",
    "        correct += pred.eq(target.data.view_as(pred)).sum()\n",
    "    test_loss /= len(test_loader.dataset)\n",
    "    print('\\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n",
    "        test_loss, correct, len(test_loader.dataset),\n",
    "        100. * correct / len(test_loader.dataset)))\n",
    "\n",
    "# 运行主程序\n",
    "for epoch in range(1, 10):\n",
    "    train(epoch)\n",
    "    test()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "notes",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
